<!-- Chat Completions Tab -->
<div id="tabChatCompletions" class="tab-content">
    <div class="endpoint-section">
        <h2>POST /api/v1/chat/completions - Chat Completions</h2>
        <p>OpenAI-compatible chat completions endpoint for interactive conversations with full parameter control.</p>

        <!-- Basic Parameters -->
        <div class="basic-params">
            <h3>Basic Parameters</h3>
            <div class="help-inline" style="font-size: 0.9em; color: #555; margin: 6px 0 12px;">
                <span title="Tip: You can either select a provider or prefix the model as provider/model (e.g., anthropic/claude-sonnet-4.5). The server parses prefixed models automatically if api_provider is not set. See the Providers tab for configured providers/models. Useful endpoints: /api/v1/llm/providers, /api/v1/llm/models.">ⓘ Provider/Model help</span>
                <a href="/docs" target="_blank" style="margin-left:8px;">Open API Docs</a>
            </div>

            <div class="form-group">
                <label for="chatCompletions_provider">API Provider:</label>
                <select id="chatCompletions_provider">
                    <option value="">Default</option>
                    <option value="openai">OpenAI</option>
                    <option value="anthropic">Anthropic</option>
                    <option value="cohere">Cohere</option>
                    <option value="deepseek">DeepSeek</option>
                    <option value="google">Google</option>
                    <option value="groq">Groq</option>
                    <option value="huggingface">HuggingFace</option>
                    <option value="mistral">Mistral</option>
                    <option value="openrouter">OpenRouter</option>
                    <option value="llama.cpp">Llama.cpp</option>
                    <option value="kobold">Kobold</option>
                    <option value="ollama">Ollama</option>
                    <option value="ooba">Oobabooga</option>
                    <option value="tabbyapi">TabbyAPI</option>
                    <option value="vllm">vLLM</option>
                    <option value="local-llm">Local LLM</option>
                    <option value="custom-openai-api">Custom OpenAI API</option>
                </select>
            </div>

            <div class="form-group">
                <label for="chatCompletions_model">Model:</label>
                <select id="chatCompletions_model" class="llm-model-select">
                    <option value="">Loading models...</option>
                </select>
            </div>

            <div class="form-group">
                <label for="chatCompletions_messages">Messages (JSON array):</label>
                <textarea id="chatCompletions_messages" style="min-height: 200px;">[
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Hello! How are you today?"}
]</textarea>
            </div>

            <div class="form-group">
                <label for="chatCompletions_temperature">Temperature:</label>
                <input type="number" id="chatCompletions_temperature" min="0" max="2" step="0.1" value="0.7">
            </div>

            <div class="form-group">
                <label for="chatCompletions_max_tokens">Max Tokens:</label>
                <input type="number" id="chatCompletions_max_tokens" value="1000">
            </div>

            <div class="form-group">
                <label>
                    <input type="checkbox" id="chatCompletions_stream"> Stream Response
                </label>
            </div>

            <div class="form-group">
                <label>
                    <input type="checkbox" id="chatCompletions_save_to_db"> Save to DB (persist conversation)
                </label>
            </div>
        </div>

        <!-- Advanced Parameters -->
        <details class="advanced-params" style="margin-top: 20px; padding: 10px; border: 1px solid #ddd; border-radius: 5px;">
            <summary style="cursor: pointer; font-weight: bold; padding: 5px;">⚙️ Advanced Options</summary>

            <!-- Sampling Parameters -->
            <fieldset style="margin-top: 15px; padding: 10px; border: 1px solid #ccc; border-radius: 3px;">
                <legend>Sampling Parameters</legend>

                <div class="form-group">
                    <label for="chatCompletions_frequency_penalty">Frequency Penalty (-2.0 to 2.0):</label>
                    <input type="number" id="chatCompletions_frequency_penalty" min="-2" max="2" step="0.1" placeholder="0">
                </div>

                <div class="form-group">
                    <label for="chatCompletions_presence_penalty">Presence Penalty (-2.0 to 2.0):</label>
                    <input type="number" id="chatCompletions_presence_penalty" min="-2" max="2" step="0.1" placeholder="0">
                </div>

                <div class="form-group">
                    <label for="chatCompletions_top_p">Top P (0.0 to 1.0):</label>
                    <input type="number" id="chatCompletions_top_p" min="0" max="1" step="0.01" placeholder="1">
                </div>

                <div class="form-group">
                    <label for="chatCompletions_top_k">Top K (integer):</label>
                    <input type="number" id="chatCompletions_top_k" min="1" step="1" placeholder="Not set">
                </div>

                <div class="form-group">
                    <label for="chatCompletions_min_p">Min P (float):</label>
                    <input type="number" id="chatCompletions_min_p" min="0" max="1" step="0.01" placeholder="Not set">
                </div>

                <div class="form-group">
                    <label for="chatCompletions_seed">Seed (for deterministic sampling):</label>
                    <input type="number" id="chatCompletions_seed" step="1" placeholder="Random">
                </div>

                <div class="form-group">
                    <label for="chatCompletions_n">Number of Completions (1-128):</label>
                    <input type="number" id="chatCompletions_n" min="1" max="128" value="1">
                </div>
            </fieldset>

            <!-- Response Control -->
            <fieldset style="margin-top: 15px; padding: 10px; border: 1px solid #ccc; border-radius: 3px;">
                <legend>Response Control</legend>

                <div class="form-group">
                    <label>Response Format:</label>
                    <div>
                        <label><input type="radio" name="chatCompletions_response_format" value="text" checked> Text</label>
                        <label style="margin-left: 20px;"><input type="radio" name="chatCompletions_response_format" value="json_object"> JSON Object</label>
                    </div>
                </div>

                <div class="form-group">
                    <label for="chatCompletions_stop">Stop Sequences (comma-separated):</label>
                    <input type="text" id="chatCompletions_stop" placeholder='e.g., "\n\n", "END", "STOP"'>
                </div>

                <div class="form-group">
                    <label for="chatCompletions_user">User Identifier:</label>
                    <input type="text" id="chatCompletions_user" placeholder="Optional user ID for monitoring">
                </div>

                <div class="form-group">
                    <label>
                        <input type="checkbox" id="chatCompletions_logprobs"> Return Log Probabilities
                    </label>
                </div>

                <div class="form-group" id="top_logprobs_group" style="display: none;">
                    <label for="chatCompletions_top_logprobs">Top Log Probabilities (0-20):</label>
                    <input type="number" id="chatCompletions_top_logprobs" min="0" max="20" value="5">
                </div>

                <div class="form-group">
                    <label for="chatCompletions_logit_bias">Logit Bias (JSON object):</label>
                    <textarea id="chatCompletions_logit_bias" rows="3" placeholder='e.g., {"50256": -100}'>{}</textarea>
                </div>
            </fieldset>

            <!-- Context & Templates -->
            <fieldset style="margin-top: 15px; padding: 10px; border: 1px solid #ccc; border-radius: 3px;">
                <legend>Context & Templates</legend>

                <div class="form-group">
                    <label for="chatCompletions_prompt_template">Prompt Template Name:</label>
                    <input type="text" id="chatCompletions_prompt_template" placeholder="Optional template name">
                </div>

                <div class="form-group">
                    <label for="chatCompletions_character_id">Character ID:</label>
                    <input type="number" id="chatCompletions_character_id" placeholder="Optional character ID">
                </div>

                <div class="form-group">
                    <label for="chatCompletions_conversation_id">Conversation ID:</label>
                    <input type="text" id="chatCompletions_conversation_id" placeholder="Optional conversation ID">
                </div>
            </fieldset>

            <!-- Function Calling -->
            <fieldset style="margin-top: 15px; padding: 10px; border: 1px solid #ccc; border-radius: 3px;">
                <legend>Function Calling / Tools</legend>

                <div class="form-group">
                    <label for="chatCompletions_tools">Tools Definition (JSON array):</label>
                    <textarea id="chatCompletions_tools" rows="5" placeholder='[{"type": "function", "function": {"name": "get_weather", "description": "Get weather", "parameters": {}}}]'>[]</textarea>
                </div>

                <div class="form-group">
                    <label for="chatCompletions_tool_choice">Tool Choice:</label>
                    <select id="chatCompletions_tool_choice">
                        <option value="auto">Auto</option>
                        <option value="none">None</option>
                        <option value="required">Required</option>
                        <option value="specific">Specific Tool (JSON)</option>
                    </select>
                </div>

                <div class="form-group" id="tool_choice_json_group" style="display: none;">
                    <label for="chatCompletions_tool_choice_json">Specific Tool (JSON):</label>
                    <textarea id="chatCompletions_tool_choice_json" rows="3" placeholder='{"type": "function", "function": {"name": "function_name"}}'>{}</textarea>
                </div>
            </fieldset>
        </details>

        <button class="api-button" id="chatCompletions_send_request" style="margin-top: 20px;">Send Request</button>

        <h3>Response:</h3>
        <pre id="chatCompletions_response">---</pre>
    </div>

    <div class="endpoint-section">
        <h2>Interactive Chat Interface</h2>
        <p class="text-muted">This same interface is now pinned to the Simple tab for quick access.</p>
        <div id="chatAdvancedHost" data-chat-host="advanced">
            <div class="chat-host-placeholder text-muted" data-chat-placeholder style="display:none;">
                Chat interface is currently shown on the Simple tab.
            </div>
            <div class="chat-interface" data-shared-chat-ui="true">
            <!-- Conversation-first Layout -->
            <div class="chat-layout">
                <!-- Left: Conversations -->
                <aside class="chat-sidebar" aria-label="Conversations">
                    <div class="sidebar-header">
                        <strong>Conversations</strong>
                        <div class="sidebar-actions">
                            <button class="btn btn-sm" id="chat-conv-refresh" title="Refresh">⟳</button>
                            <button class="btn btn-sm" id="chat-conv-new" title="New conversation">＋</button>
                        </div>
                    </div>
                    <div class="sidebar-search">
                        <input type="search" id="chat-conv-search" placeholder="Search conversations..." aria-label="Search conversations">
                    </div>
                    <div id="chat-conversations-list" class="conversations-list" aria-live="polite"></div>
                </aside>

                <!-- Center: Messages -->
                <section class="chat-main" aria-label="Messages">
                    <!-- Toolbar: model/provider/presets -->
                    <div class="chat-toolbar">
                        <div class="toolbar-left">
                            <label class="muted" for="chat-provider">Provider</label>
                            <select id="chat-provider" title="You can also set the model as provider/model without selecting a provider here.">
                                <option value="">All Providers</option>
                                <option value="openai">OpenAI</option>
                                <option value="anthropic">Anthropic</option>
                                <option value="cohere">Cohere</option>
                                <option value="deepseek">DeepSeek</option>
                                <option value="google">Google</option>
                                <option value="groq">Groq</option>
                                <option value="huggingface">HuggingFace</option>
                                <option value="mistral">Mistral</option>
                                <option value="openrouter">OpenRouter</option>
                                <option value="llama.cpp">Llama.cpp</option>
                                <option value="kobold">Kobold</option>
                                <option value="ollama">Ollama</option>
                                <option value="ooba">Oobabooga</option>
                                <option value="tabbyapi">TabbyAPI</option>
                                <option value="vllm">vLLM</option>
                                <option value="local-llm">Local LLM</option>
                                <option value="custom-openai-api">Custom OpenAI API</option>
                            </select>
                            <label class="muted" for="chat-model">Model</label>
                            <div class="model-picker">
                                <input id="chat-model-search" type="search" placeholder="Search models..." aria-label="Search models">
                                <select id="chat-model" class="llm-model-select"></select>
                            </div>
                        </div>
                        <div class="toolbar-right">
                            <label class="muted" for="chat-preset-select">Preset</label>
                            <select id="chat-preset-select" title="Apply a chat preset (system + sampling)">
                                <option value="">None</option>
                            </select>
                            <a href="/chat" target="_blank" rel="noopener noreferrer" class="btn" title="Open the React chat UI">Open React Chat ↗</a>
                        </div>
                    </div>

                    <!-- System Prompt (compact) -->
                    <div class="system-prompt-row">
                        <label for="chat-system-prompt" class="muted">System Prompt</label>
                        <textarea id="chat-system-prompt" placeholder="Enter system prompt...">You are a helpful assistant.</textarea>
                        <button class="btn btn-sm" id="chat-update-system" title="Update system message in history">Apply</button>
                    </div>

                    <div id="chat-messages" class="chat-messages" aria-live="polite">
                        <div class="chat-message system">
                            <div class="bubble">
                                <div class="content">System: You are a helpful assistant.</div>
                            </div>
                        </div>
                        <button id="chat-jump-latest" class="chat-jump-latest" style="display:none;" title="Jump to latest">Jump to latest ↓</button>
                    </div>

                    <!-- Composer (sticky) -->
                    <div class="chat-composer" aria-label="Message composer">
                        <div class="composer-row">
                            <textarea id="chat-input" placeholder="Type your message..."></textarea>
                            <div class="composer-attachments">
                                <input type="file" id="chat-attach" accept="image/*" style="display:none;">
                                <button class="btn" id="chat-attach-btn" title="Attach image">🖼️</button>
                                <div id="chat-attach-preview" class="attach-preview" style="display:none;">
                                    <img alt="attachment preview">
                                    <button class="btn btn-sm btn-danger" id="chat-attach-remove" title="Remove attachment">✕</button>
                                </div>
                            </div>
                        </div>
                        <div class="composer-hint" id="chat-enter-hint">Enter to send • Shift+Enter for newline</div>
                        <div class="composer-controls">
                            <div class="left-controls">
                                <label><input type="checkbox" id="chat-enter-to-send" checked> Enter to send</label>
                                <label><input type="checkbox" id="chat-stream"> Stream</label>
                                <label><input type="checkbox" id="chat-save-to-db"> Save to DB</label>
                                <label><input type="checkbox" id="chat-auto-continue"> Auto-continue</label>
                                <label><input type="checkbox" id="chat-scroll-lock"> Scroll lock</label>
                            </div>
                            <div class="sampling-controls">
                                <label for="chat-temp" class="muted">Temp</label>
                                <input id="chat-temp" type="number" min="0" max="2" step="0.1" value="0.7">
                                <label for="chat-top-p" class="muted">top_p</label>
                                <input id="chat-top-p" type="number" min="0" max="1" step="0.01" value="1">
                                <label for="chat-max-tokens" class="muted">max_tokens</label>
                                <input id="chat-max-tokens" type="number" min="1" step="1" value="1000">
                            </div>
                            <div class="right-controls">
                                <button class="btn btn-secondary" id="chat-clear-btn" aria-label="Clear chat history">Clear</button>
                                <button class="btn" id="chat-copy-last-btn" title="Copy last answer">Copy</button>
                                <button class="btn" id="chat-retry-btn" title="Retry last user message">Retry</button>
                                <button class="btn" id="chat-edit-last-btn" title="Edit last user message inline">Edit</button>
                                <button class="btn btn-warning" id="chat-stop-btn" aria-label="Stop streaming" style="display:none;">Stop</button>
                                <button class="btn btn-primary" id="chat-send-btn" aria-label="Send message">Send</button>
                                <button class="btn" id="chat-continue-btn" title="Continue conversation" style="display:none;">Continue</button>
                            </div>
                        </div>
                        <div class="composer-meta">
                            <label for="chat-conversation-id" class="muted">Conversation ID</label>
                            <input id="chat-conversation-id" type="text" readonly placeholder="(not set)">
                            <button class="btn btn-sm" id="chat-reset-conv" title="Clear conversation id">Reset</button>
                        </div>
                    </div>
                </section>

                <!-- Right: Context/Tools -->
                <aside class="chat-right" aria-label="Context and tools">
                    <div class="card">
                        <div class="card-title">Tools</div>
                        <div id="chat-tools-log" class="tools-log"></div>
                    </div>
                    <div class="card">
                        <div class="card-title">Tips</div>
                        <div class="muted" style="font-size:0.9em;">
                            - Use presets to quickly change behavior.<br>
                            - Scroll lock prevents auto-scrolling during long streams.<br>
                            - Attach an image to send vision prompts.
                        </div>
                    </div>
                </aside>
            </div>
            </div>
        </div>
    </div>
</div>

<!-- Chat Dictionaries Tab -->
<div id="tabDictionaries" class="tab-content">
    <div class="endpoint-section">
        <h2>Chat Dictionaries</h2>
        <p>Create and manage text replacement dictionaries. Supports literal and regex patterns, probabilities, and groups.</p>

        <div class="grid-2" style="display:grid; grid-template-columns: 1fr 1fr; gap: 16px; align-items:start;">
            <!-- Left: Dictionaries List & Create -->
            <div>
                <div class="card" style="padding:12px;">
                    <div style="display:flex; gap:8px; align-items:center; justify-content:space-between;">
                        <strong>Dictionaries</strong>
                        <div style="display:flex; gap:8px;">
                            <button class="api-button" id="dictsRefreshBtn">Refresh</button>
                        </div>
                    </div>
                    <div id="dictsList" style="margin-top:8px;"></div>
                </div>

                <div class="card" style="padding:12px; margin-top:12px;">
                    <strong>Create Dictionary</strong>
                    <div class="form-group">
                        <label for="dictCreate_name">Name</label>
                        <input type="text" id="dictCreate_name" placeholder="My Dictionary">
                    </div>
                    <div class="form-group">
                        <label for="dictCreate_description">Description</label>
                        <input type="text" id="dictCreate_description" placeholder="Optional description">
                    </div>
                    <button class="api-button" id="dictCreateBtn">Create</button>
                    <div id="dictCreate_status" class="muted" style="margin-top:6px;"></div>
                </div>
            </div>

            <!-- Right: Selected Dictionary Details -->
            <div>
                <div class="card" style="padding:12px;">
                    <div style="display:flex; align-items:center; justify-content:space-between; gap:8px;">
                        <div>
                            <strong>Selected Dictionary:</strong>
                            <span id="selectedDictName" class="muted">None</span>
                        </div>
                        <div>
                            <button class="api-button" id="dictToggleActiveBtn" disabled>Toggle Active</button>
                            <button class="btn btn-danger" id="dictDeleteBtn" disabled>Delete</button>
                        </div>
                    </div>
                    <div id="selectedDictMeta" class="muted" style="margin-top:6px;"></div>
                </div>

                <div class="card" style="padding:12px; margin-top:12px;">
                    <div style="display:flex; align-items:center; justify-content:space-between;">
                        <strong>Entries</strong>
                        <div style="display:flex; gap:8px; align-items:center; flex-wrap:wrap;">
                            <input type="text" id="entriesFilter" placeholder="Filter entries by pattern..." style="width:220px;">
                            <select id="entriesTypeFilter">
                                <option value="">All types</option>
                                <option value="literal">literal</option>
                                <option value="regex">regex</option>
                            </select>
                            <select id="entriesGroupFilter">
                                <option value="">All groups</option>
                            </select>
                            <label style="display:flex; gap:6px; align-items:center;">
                                <input type="checkbox" id="entriesGroupBy"> Group by group
                            </label>
                        </div>
                    </div>
                    <div style="display:flex; gap:8px; align-items:center; margin-top:8px;">
                        <label style="display:flex; gap:6px; align-items:center;">
                            <input type="checkbox" id="entriesSelectAll"> Select all
                        </label>
                        <select id="bulkAction">
                            <option value="">Bulk action...</option>
                            <option value="activate">Activate</option>
                            <option value="deactivate">Deactivate</option>
                            <option value="delete">Delete</option>
                            <option value="group">Set Group</option>
                            <option value="rename_group">Rename Group</option>
                            <option value="clear_group">Clear Group</option>
                        </select>
                        <input type="text" id="bulkGroupName" placeholder="Group name" style="display:none;"/>
                        <button class="api-button" id="bulkApplyBtn">Apply</button>
                    </div>
                    <div id="entriesList" style="margin:8px 0; max-height:280px; overflow:auto; border:1px solid var(--color-border); border-radius:6px; padding:8px; background:var(--color-surface-alt);"></div>

                    <details style="margin-top:8px;">
                        <summary><strong>Add Entry</strong></summary>
                        <div class="form-group">
                            <label for="entry_pattern">Pattern</label>
                            <input type="text" id="entry_pattern" placeholder="e.g., AI or \\b(\\d+)F\\b">
                        </div>
                        <div class="form-group">
                            <label for="entry_replacement">Replacement</label>
                            <input type="text" id="entry_replacement" placeholder="Replacement text">
                        </div>
                        <div class="form-group" style="display:flex; gap:8px;">
                            <div style="flex:1;">
                                <label for="entry_type">Type</label>
                                <select id="entry_type">
                                    <option value="literal">literal</option>
                                    <option value="regex">regex</option>
                                </select>
                            </div>
                            <div style="flex:1;">
                                <label for="entry_probability">Probability (0.0-1.0)</label>
                                <input type="number" step="0.05" min="0" max="1" id="entry_probability" value="1.0">
                            </div>
                        </div>
                        <div class="form-group" style="display:flex; gap:8px;">
                            <div style="flex:1;">
                                <label for="entry_group">Group (optional)</label>
                                <input type="text" id="entry_group" placeholder="group name">
                            </div>
                            <div style="flex:1;">
                                <label for="entry_max_replacements">Max Replacements (0 = unlimited)</label>
                                <input type="number" min="0" id="entry_max_replacements" value="0">
                            </div>
                        </div>
                        <div class="form-group" style="display:flex; gap:16px;">
                            <label><input type="checkbox" id="entry_enabled" checked> Enabled</label>
                            <label><input type="checkbox" id="entry_case_sensitive" checked> Case Sensitive (literal)</label>
                        </div>
                        <button class="api-button" id="entryAddBtn">Add Entry</button>
                        <div id="entryAdd_status" class="muted" style="margin-top:6px;"></div>
                    </details>
                </div>

                <div class="card" style="padding:12px; margin-top:12px;">
                    <strong>Process Sample Text</strong>
                    <div class="form-group">
                        <label for="proc_text">Text</label>
                        <textarea id="proc_text" rows="3" placeholder="Enter text to process..."></textarea>
                    </div>
                    <div class="form-group" style="display:flex; gap:8px;">
                        <div style="flex:1;">
                            <label for="proc_max_tokens">Max Tokens (optional)</label>
                            <input type="number" id="proc_max_tokens" placeholder="e.g., 100">
                        </div>
                        <div style="flex:1;">
                            <label for="proc_group">Group (optional)</label>
                            <input type="text" id="proc_group" placeholder="group name">
                        </div>
                    </div>
                    <button class="api-button" id="procRunBtn">Process</button>
                    <div class="form-group">
                        <label>Processed Output</label>
                        <pre id="proc_output" style="min-height:60px; overflow:auto; white-space:pre-wrap;"></pre>
                        <small id="proc_stats" class="muted"></small>
                    </div>
                </div>

                <div class="card" style="padding:12px; margin-top:12px;">
                    <strong>Import / Export</strong>
                    <details>
                        <summary>Import from Markdown</summary>
                        <div class="form-group">
                            <label for="imp_name">Dictionary Name</label>
                            <input type="text" id="imp_name" placeholder="Imported Dictionary">
                        </div>
                        <div class="form-group">
                            <label for="imp_content">Markdown Content</label>
                            <textarea id="imp_content" rows="6" placeholder="# My Dict\n\n## Entry: AI\n- **Type**: literal\n- **Replacement**: Artificial Intelligence\n- **Enabled**: true"></textarea>
                        </div>
                        <label><input type="checkbox" id="imp_activate" checked> Activate after import</label>
                        <div>
                            <button class="api-button" id="impRunBtn">Import</button>
                            <span id="imp_status" class="muted" style="margin-left:8px;"></span>
                        </div>
                    </details>
                    <details style="margin-top:8px;">
                        <summary>Export to Markdown</summary>
                        <div style="display:flex; gap:8px; align-items:center; flex-wrap:wrap;">
                            <button class="api-button" id="expRunBtn">Export</button>
                            <button class="btn" id="expDownloadMdBtn">Download Markdown</button>
                            <button class="btn" id="expCopyMdBtn">Copy</button>
                        </div>
                        <div class="form-group" style="margin-top:8px;">
                            <label>Exported Content</label>
                            <textarea id="exp_content" rows="6" readonly></textarea>
                        </div>
                    </details>
                    <details style="margin-top:8px;">
                        <summary>JSON Import / Export</summary>
                        <div style="display:flex; gap:12px; flex-wrap:wrap;">
                            <div style="flex:1; min-width:280px;">
                                <strong>Export JSON</strong>
                                <div style="display:flex; gap:8px; align-items:center; flex-wrap:wrap;">
                                    <button class="api-button" id="expJsonBtn">Export JSON</button>
                                    <button class="btn" id="expJsonDownloadBtn">Download JSON</button>
                                    <button class="btn" id="expJsonCopyBtn">Copy</button>
                                </div>
                                <div class="form-group" style="margin-top:8px;">
                                    <label>JSON</label>
                                    <textarea id="exp_json_content" rows="6" readonly></textarea>
                                </div>
                            </div>
                            <div style="flex:1; min-width:280px;">
                                <strong>Import JSON</strong>
                                <div class="form-group">
                                    <label for="imp_json_content">JSON (Drag & Drop file to load)</label>
                                    <textarea id="imp_json_content" rows="6" placeholder='{"name":"My Dict","entries":[{"pattern":"AI","replacement":"Artificial Intelligence","type":"literal"}]}'></textarea>
                                </div>
                                <label><input type="checkbox" id="imp_json_activate" checked> Activate after import</label>
                                <div>
                                    <button class="api-button" id="impJsonBtn">Import JSON</button>
                                    <span id="imp_json_status" class="muted" style="margin-left:8px;"></span>
                                </div>
                            </div>
                        </div>
                    </details>
                    <details style="margin-top:8px;">
                        <summary>CSV Import / Export</summary>
                        <div style="display:flex; gap:12px; flex-wrap:wrap;">
                            <div style="flex:1; min-width:280px;">
                                <strong>Export CSV</strong>
                                <div style="display:flex; gap:8px; align-items:center; flex-wrap:wrap;">
                                    <button class="api-button" id="expCsvBtn">Export CSV</button>
                                    <button class="btn" id="expCsvDownloadBtn">Download CSV</button>
                                    <button class="btn" id="expCsvCopyBtn">Copy</button>
                                </div>
                                <div class="form-group" style="margin-top:8px;">
                                    <label>CSV</label>
                                    <textarea id="exp_csv_content" rows="6" readonly placeholder="pattern,replacement,type,probability,enabled,case_sensitive,group,max_replacements\n..."></textarea>
                                </div>
                            </div>
                            <div style="flex:1; min-width:280px;">
                                <strong>Import CSV</strong>
                                <div class="form-group">
                                    <label for="imp_csv_name">Dictionary Name</label>
                                    <input type="text" id="imp_csv_name" placeholder="Imported CSV Dictionary">
                                </div>
                                <div class="form-group">
                                    <label for="imp_csv_content">CSV (Drag & Drop file to load)</label>
                                    <textarea id="imp_csv_content" rows="6" placeholder="pattern,replacement,type,probability,enabled,case_sensitive,group,max_replacements\nAI,Artificial Intelligence,literal,1.0,true,true,,0"></textarea>
                                </div>
                                <label><input type="checkbox" id="imp_csv_activate" checked> Activate after import</label>
                                <div>
                                    <button class="api-button" id="impCsvBtn">Import CSV</button>
                                    <span id="imp_csv_status" class="muted" style="margin-left:8px;"></span>
                                </div>
                            </div>
                        </div>
                    </details>
                </div>
            </div>
        </div>
    </div>
</div>

<!-- Character Management Tab -->
<div id="tabCharacterManagement" class="tab-content">
    <div class="endpoint-section" id="importCharacter">
        <h2>POST /api/v1/characters/import - Import Character from File</h2>
        <p>Supports PNG/WEBP (with 'chara' metadata), JSON, or Markdown files.</p>
        <div class="form-group">
            <label for="importCharacter_character_file">Character File:</label>
            <input type="file" id="importCharacter_character_file" name="character_file" accept=".png,.webp,.json,.md">
        </div>
        <button class="api-button" data-action="exec-endpoint" data-id="importCharacter" data-method="POST" data-path="/api/v1/characters/import" data-body="form">Send Request</button>
        <h3>cURL Command:</h3>
        <pre id="importCharacter_curl">---</pre>
        <h3>Response:</h3>
        <pre id="importCharacter_response">---</pre>
    </div>

    <div class="endpoint-section" id="listCharacters">
        <h2>GET /api/v1/characters/ - List All Characters</h2>
        <div class="form-group">
            <label for="listCharacters_limit">Limit:</label>
            <input type="number" id="listCharacters_limit" name="limit" value="100">
        </div>
        <div class="form-group">
            <label for="listCharacters_offset">Offset:</label>
            <input type="number" id="listCharacters_offset" name="offset" value="0">
        </div>
        <button class="api-button" data-action="exec-endpoint" data-id="listCharacters" data-method="GET" data-path="/api/v1/characters/" data-body="query">Send Request</button>
        <h3>cURL Command:</h3>
        <pre id="listCharacters_curl">---</pre>
        <h3>Response:</h3>
        <pre id="listCharacters_response">---</pre>
    </div>

    <div class="endpoint-section" id="createCharacter">
        <h2>POST /api/v1/characters/ - Create Character</h2>
        <div class="form-group">
            <label for="createCharacter_payload">Payload (CharacterCreate JSON):</label>
            <textarea id="createCharacter_payload" style="min-height: 300px;">{
    "name": "Sir Gideon",
    "description": "A valiant knight from the forgotten ages.",
    "personality": "Brave, honorable, somewhat stoic but kind-hearted.",
    "scenario": "Guarding the Whispering Pass against encroaching shadows.",
    "system_prompt": "You are Sir Gideon, a knight of old. Speak with honor and courage. Offer guidance to those who seek it. You are currently at the Whispering Pass.",
    "post_history_instructions": "Maintain your persona as Sir Gideon. Be wary of trickery.",
    "first_message": "Hail, traveler! What brings you to this perilous Whispering Pass?",
    "message_example": "<START>\nUSER: Greetings, Sir Knight. What dangers lie ahead?\nASSISTANT: The path is fraught with peril, good sir. Shadow beasts roam these lands, and the very air grows cold with their passing. State your purpose, and perhaps I can offer counsel.\n<END>",
    "creator_notes": "This is a character for a fantasy RPG setting. Focus on medieval speech patterns.",
    "alternate_greetings": ["Well met, adventurer!", "Who goes there? Declare yourself!"],
    "tags": ["fantasy", "knight", "guardian", "lore"],
    "creator": "AI Storyteller",
    "character_version": "1.0.0",
    "extensions": {
        "world_setting": "Kingdom of Eldoria",
        "faction": "Knights of the Silver Flame",
        "inventory_system_notes": "Standard D&D 5e equipment. Has a +1 longsword."
    },
    "image_base64": null
}</textarea>
            <small><code>image_base64</code> should be a base64 encoded string of the image, without the 'data:image/...;base64,' prefix. List/Dict fields can be JSON strings or actual lists/dicts if using a client that sends structured JSON.</small>
        </div>
        <button class="api-button" data-action="exec-endpoint" data-id="createCharacter" data-method="POST" data-path="/api/v1/characters/" data-body="json">Send Request</button>
        <h3>cURL Command:</h3>
        <pre id="createCharacter_curl">---</pre>
        <h3>Response:</h3>
        <pre id="createCharacter_response">---</pre>
    </div>

    <div class="endpoint-section" id="getCharacter">
        <h2>GET /api/v1/characters/{character_id} - Get Character</h2>
        <div class="form-group">
            <label for="getCharacter_character_id">Character ID:</label>
            <input type="number" id="getCharacter_character_id" value="1">
        </div>
        <button class="api-button" data-action="exec-endpoint" data-id="getCharacter" data-method="GET" data-path="/api/v1/characters/{character_id}" data-body="none">Send Request</button>
        <h3>cURL Command:</h3>
        <pre id="getCharacter_curl">---</pre>
        <h3>Response:</h3>
        <pre id="getCharacter_response">---</pre>
    </div>

    <div class="endpoint-section" id="updateCharacter">
        <h2>PUT /api/v1/characters/{character_id} - Update Character</h2>
        <div class="form-group">
            <label for="updateCharacter_character_id">Character ID:</label>
            <input type="number" id="updateCharacter_character_id" value="1">
        </div>
        <div class="form-group">
            <label for="updateCharacter_payload">Payload (CharacterUpdate JSON - include only fields to change):</label>
            <textarea id="updateCharacter_payload" style="min-height: 250px;">{
    "description": "An even braver knight, now with a slightly shinier helmet.",
    "tags": ["fantasy", "knight", "updated"],
    "image_base64": null
}</textarea>
            <small>To remove an image, pass <code>image_base64: null</code> or an empty string.</small>
        </div>
        <button class="api-button" data-action="exec-endpoint" data-id="updateCharacter" data-method="PUT" data-path="/api/v1/characters/{character_id}" data-body="json">Send Request</button>
        <h3>cURL Command:</h3>
        <pre id="updateCharacter_curl">---</pre>
        <h3>Response:</h3>
        <pre id="updateCharacter_response">---</pre>
    </div>

    <div class="endpoint-section" id="deleteCharacter">
        <h2>DELETE /api/v1/characters/{character_id} - Delete Character</h2>
        <div class="form-group">
            <label for="deleteCharacter_character_id">Character ID:</label>
            <input type="number" id="deleteCharacter_character_id" value="1">
        </div>
        <button class="api-button" data-action="exec-endpoint" data-id="deleteCharacter" data-method="DELETE" data-path="/api/v1/characters/{character_id}" data-body="none">Send Request</button>
        <h3>cURL Command:</h3>
        <pre id="deleteCharacter_curl">---</pre>
        <h3>Response:</h3>
        <pre id="deleteCharacter_response">---</pre>
    </div>

    <div class="endpoint-section" id="exportCharacter">
        <h2>GET /api/v1/characters/{character_id}/export - Export Character</h2>
        <p>Export a character in various formats.</p>
        <div class="form-group">
            <label for="exportCharacter_character_id">Character ID:</label>
            <input type="number" id="exportCharacter_character_id" value="1">
        </div>
        <div class="form-group">
            <label for="exportCharacter_format">Export Format:</label>
            <select id="exportCharacter_format">
                <option value="json">JSON</option>
                <option value="png">PNG (with metadata)</option>
                <option value="markdown">Markdown</option>
            </select>
        </div>
        <button class="api-button" id="btn_exportCharacter">Export Character</button>
        <h3>Response:</h3>
        <pre id="exportCharacter_response">---</pre>
    </div>
</div>

<!-- Scripts removed - functions now in js/tab-functions.js -->
<!-- <script>
// Helper functions for UI interactions
function toggleLogprobs() {
    const logprobsChecked = document.getElementById('chatCompletions_logprobs').checked;
    document.getElementById('top_logprobs_group').style.display = logprobsChecked ? 'block' : 'none';
}

function toggleToolChoiceJSON() {
    const toolChoice = document.getElementById('chatCompletions_tool_choice').value;
    document.getElementById('tool_choice_json_group').style.display = toolChoice === 'specific' ? 'block' : 'none';
}

// Chat Completions functionality - Now collects ALL parameters
async function makeChatCompletionsRequest() {
    const responseEl = document.getElementById('chatCompletions_response');

    try {
        // Build the payload with all parameters
        const payload = {};

        // Basic Parameters
        const provider = document.getElementById('chatCompletions_provider').value;
        if (provider) payload.api_provider = provider;

        const model = document.getElementById('chatCompletions_model').value;
        if (model) payload.model = model;

        const messagesText = document.getElementById('chatCompletions_messages').value;
        try {
            const parsedMessages = JSON.parse(messagesText);
            if (!Array.isArray(parsedMessages)) {
                throw new Error('Messages must be an array');
            }
            payload.messages = parsedMessages;
        } catch (e) {
            throw new Error('Invalid messages JSON format: ' + e.message);
        }

        const temperature = parseFloat(document.getElementById('chatCompletions_temperature').value);
        if (!isNaN(temperature)) payload.temperature = temperature;

        const maxTokens = parseInt(document.getElementById('chatCompletions_max_tokens').value);
        if (!isNaN(maxTokens)) payload.max_tokens = maxTokens;

        payload.stream = document.getElementById('chatCompletions_stream').checked;

        // Sampling Parameters
        const frequencyPenalty = parseFloat(document.getElementById('chatCompletions_frequency_penalty').value);
        if (!isNaN(frequencyPenalty)) payload.frequency_penalty = frequencyPenalty;

        const presencePenalty = parseFloat(document.getElementById('chatCompletions_presence_penalty').value);
        if (!isNaN(presencePenalty)) payload.presence_penalty = presencePenalty;

        const topP = parseFloat(document.getElementById('chatCompletions_top_p').value);
        if (!isNaN(topP)) payload.top_p = topP;

        const topK = parseInt(document.getElementById('chatCompletions_top_k').value);
        if (!isNaN(topK)) payload.topk = topK;

        const minP = parseFloat(document.getElementById('chatCompletions_min_p').value);
        if (!isNaN(minP)) payload.minp = minP;

        const seed = parseInt(document.getElementById('chatCompletions_seed').value);
        if (!isNaN(seed)) payload.seed = seed;

        const n = parseInt(document.getElementById('chatCompletions_n').value);
        if (!isNaN(n)) payload.n = n;

        // Response Control
        const responseFormat = document.querySelector('input[name="chatCompletions_response_format"]:checked').value;
        if (responseFormat === 'json_object') {
            payload.response_format = { type: 'json_object' };
        }

        const stopSequences = document.getElementById('chatCompletions_stop').value;
        if (stopSequences) {
            // Parse comma-separated values
            payload.stop = stopSequences.split(',').map(s => s.trim()).filter(s => s);
        }

        const user = document.getElementById('chatCompletions_user').value;
        if (user) payload.user = user;

        const logprobs = document.getElementById('chatCompletions_logprobs').checked;
        if (logprobs) {
            payload.logprobs = true;
            const topLogprobs = parseInt(document.getElementById('chatCompletions_top_logprobs').value);
            if (!isNaN(topLogprobs)) payload.top_logprobs = topLogprobs;
        }

        const logitBiasText = document.getElementById('chatCompletions_logit_bias').value;
        if (logitBiasText && logitBiasText !== '{}') {
            try {
                try {
                    const parsed = JSON.parse(logitBiasText);
                    if (parsed && typeof parsed === 'object') {
                        payload.logit_bias = parsed;
                    }
                } catch (e) {
                    console.warn('Invalid logit bias JSON:', e);
                }
            } catch (e) {
                console.warn('Invalid logit bias JSON:', e);
            }
        }

        // Context & Templates
        const promptTemplate = document.getElementById('chatCompletions_prompt_template').value;
        if (promptTemplate) payload.prompt_template_name = promptTemplate;

        const characterIdStr = document.getElementById('chatCompletions_character_id').value;
        if (characterIdStr) {
            const characterId = parseInt(characterIdStr);
            if (!isNaN(characterId) && characterId > 0) {
                payload.character_id = characterId;
            } else {
                console.warn('Invalid character ID:', characterIdStr);
            }
        }

        const conversationId = document.getElementById('chatCompletions_conversation_id').value;
        if (conversationId) {
            // Basic validation for conversation ID
            if (/^[a-zA-Z0-9_-]+$/.test(conversationId)) {
                payload.conversation_id = conversationId;
            } else {
                console.warn('Invalid conversation ID format:', conversationId);
            }
        }

        // Function Calling
        const toolsText = document.getElementById('chatCompletions_tools').value;
        if (toolsText && toolsText !== '[]') {
            try {
                try {
                    const parsedTools = JSON.parse(toolsText);
                    if (parsedTools && Array.isArray(parsedTools)) {
                        payload.tools = parsedTools;
                    }
                } catch (e) {
                    console.warn('Invalid tools JSON:', e);
                }
            } catch (e) {
                console.warn('Invalid tools JSON:', e);
            }
        }

        const toolChoice = document.getElementById('chatCompletions_tool_choice').value;
        if (toolChoice === 'specific') {
            const toolChoiceJSON = document.getElementById('chatCompletions_tool_choice_json').value;
            if (toolChoiceJSON && toolChoiceJSON !== '{}') {
                try {
                    try {
                        const parsed = JSON.parse(toolChoiceJSON);
                        if (parsed) {
                            payload.tool_choice = parsed;
                        }
                    } catch (e) {
                        console.warn('Invalid tool choice JSON:', e);
                    }
                } catch (e) {
                    console.warn('Invalid tool choice JSON:', e);
                }
            }
        } else if (toolChoice !== 'auto') {
            payload.tool_choice = toolChoice;
        }

        // Display the request payload for debugging
        console.log('Request payload:', payload);
        responseEl.textContent = 'Sending request with parameters:\n' + JSON.stringify(payload, null, 2) + '\n\n';

        if (payload.stream) {
            // Handle streaming response
            responseEl.textContent += 'Streaming response:\n';
            const response = await apiClient.post('/api/v1/chat/completions', payload, {
                streaming: true,
                onProgress: (chunk) => {
                    if (chunk.choices && chunk.choices[0] && chunk.choices[0].delta && chunk.choices[0].delta.content) {
                        responseEl.textContent += chunk.choices[0].delta.content;
                    }
                }
            });
            responseEl.textContent += '\n\n[Stream Complete]';
        } else {
            // Handle regular response
            const response = await apiClient.post('/api/v1/chat/completions', payload);
            responseEl.textContent += '\nResponse:\n' + JSON.stringify(response, null, 2);
        }
    } catch (error) {
        responseEl.textContent = `Error: ${error.message}`;
        console.error('Chat completions error:', error);
    }
}

// Interactive chat interface
const MAX_CHAT_MESSAGES = 100; // Limit chat history for performance
let chatMessages = [
    {role: 'system', content: 'You are a helpful assistant.'}
];

async function sendChatMessage() {
    const input = document.getElementById('chat-input');
    const messagesDiv = document.getElementById('chat-messages');
    const model = document.getElementById('chat-model').value;

    if (!input.value.trim()) return;

    const userMessage = input.value;
    input.value = '';

    // Add user message to display
    const userDiv = document.createElement('div');
    userDiv.className = 'chat-message user';
    // Create user message elements safely
    const userLabel = document.createElement('strong');
    userLabel.textContent = 'User:';
    const userContent = document.createElement('span');
    userContent.textContent = userMessage;
    userDiv.appendChild(userLabel);
    userDiv.appendChild(document.createTextNode(' '));
    userDiv.appendChild(userContent);
    messagesDiv.appendChild(userDiv);

    // Add to messages array
    chatMessages.push({role: 'user', content: userMessage});

    // Create assistant message placeholder
    const assistantDiv = document.createElement('div');
    assistantDiv.className = 'chat-message assistant';
    const assistantLabel = document.createElement('strong');
    assistantLabel.textContent = 'Assistant:';
    const assistantContent = document.createElement('span');
    assistantContent.className = 'typing';
    assistantContent.textContent = 'Thinking...';
    assistantDiv.appendChild(assistantLabel);
    assistantDiv.appendChild(document.createTextNode(' '));
    assistantDiv.appendChild(assistantContent);
    messagesDiv.appendChild(assistantDiv);

    // Use requestAnimationFrame for smooth scrolling
    requestAnimationFrame(() => {
        messagesDiv.scrollTop = messagesDiv.scrollHeight;
    });

    try {
        const response = await apiClient.post('/api/v1/chat/completions', {
            model: model,
            messages: chatMessages,
            temperature: 0.7,
            max_tokens: 1000
        });

        if (response.choices && response.choices[0] && response.choices[0].message) {
            const assistantMessage = response.choices[0].message.content;
            chatMessages.push({role: 'assistant', content: assistantMessage});
            assistantDiv.innerHTML = '';
            const label = document.createElement('strong');
            label.textContent = 'Assistant:';
            const content = document.createElement('span');
            content.textContent = assistantMessage;
            assistantDiv.appendChild(label);
            assistantDiv.appendChild(document.createTextNode(' '));
            assistantDiv.appendChild(content);
        } else {
            assistantDiv.innerHTML = '';
            const label2 = document.createElement('strong');
            label2.textContent = 'Assistant:';
            const error = document.createElement('em');
            error.textContent = 'No response received';
            assistantDiv.appendChild(label2);
            assistantDiv.appendChild(document.createTextNode(' '));
            assistantDiv.appendChild(error);
        }
    } catch (error) {
        assistantDiv.innerHTML = '';
        const errorLabel = document.createElement('strong');
        errorLabel.textContent = 'Assistant:';
        const errorMsg = document.createElement('em');
        errorMsg.textContent = `Error: ${error.message}`;
        assistantDiv.appendChild(errorLabel);
        assistantDiv.appendChild(document.createTextNode(' '));
        assistantDiv.appendChild(errorMsg);
        console.error('Chat error:', error);
    }

    // Use requestAnimationFrame for smooth scrolling
    requestAnimationFrame(() => {
        messagesDiv.scrollTop = messagesDiv.scrollHeight;
    });
}

function clearChat() {
    chatMessages = [
        {role: 'system', content: 'You are a helpful assistant.'}
    ];
    const messagesDiv = document.getElementById('chat-messages');
    messagesDiv.innerHTML = '';
    const systemDiv = document.createElement('div');
    systemDiv.className = 'chat-message system';
    systemDiv.textContent = 'System: You are a helpful assistant.';
    messagesDiv.appendChild(systemDiv);
}

// Character export functionality
async function exportCharacter() {
    const characterId = document.getElementById('exportCharacter_character_id').value;
    const format = document.getElementById('exportCharacter_format').value;
    const responseEl = document.getElementById('exportCharacter_response');

    try {
        responseEl.textContent = 'Exporting...';

        const response = await apiClient.get(`/api/v1/characters/${characterId}/export`, {
            format: format
        });

        if (format === 'json' || format === 'markdown') {
            responseEl.textContent = typeof response === 'string' ? response : JSON.stringify(response, null, 2);
        } else {
            // For PNG export, we'd need to handle binary data differently
            responseEl.textContent = 'PNG export successful. Binary data received.';
        }
    } catch (error) {
        responseEl.textContent = `Error: ${error.message}`;
    }
}

// Make functions globally available immediately
(function() {
    if (typeof window !== 'undefined') {
        window.toggleLogprobs = toggleLogprobs;
        window.toggleToolChoiceJSON = toggleToolChoiceJSON;
        window.makeChatCompletionsRequest = makeChatCompletionsRequest;
        window.sendChatMessage = sendChatMessage;
        window.clearChat = clearChat;
        window.exportCharacter = exportCharacter;

        // Also ensure they're available on the global object
        if (!window.makeChatCompletionsRequest) {
            console.error('Failed to attach makeChatCompletionsRequest to window');
        } else {
            console.log('Chat functions successfully attached to window');
        }
    }
})();

// Handle Enter key in chat input
document.addEventListener('DOMContentLoaded', () => {
    const chatInput = document.getElementById('chat-input');
    if (chatInput) {
        chatInput.addEventListener('keydown', (e) => {
            if (e.key === 'Enter' && !e.shiftKey) {
                e.preventDefault();
                sendChatMessage();
            }
        });
    }
});

// Initialize chat completions tab
function initializeChatCompletionsTab() {
    console.log('Chat Completions tab initialized');
    // Populate model dropdowns when tab is initialized
    populateModelDropdowns();
}

// Populate all model dropdowns with available LLM providers and models
async function populateModelDropdowns() {
    try {
        // Get available providers from API
        const providersInfo = await apiClient.getAvailableProviders();

        if (!providersInfo || !providersInfo.providers || providersInfo.providers.length === 0) {
            console.warn('No LLM providers configured');
            // Update dropdowns to show no providers available
            document.querySelectorAll('.llm-model-select').forEach(select => {
                // Build via DOM APIs to avoid innerHTML
                while (select.firstChild) select.removeChild(select.firstChild);
                const opt = document.createElement('option');
                opt.value = '';
                opt.textContent = 'No models available - check configuration';
                select.appendChild(opt);
            });
            return;
        }

        // Build options HTML grouped by provider (escaped)
        let optionsHtml = '';
        const defaultProvider = providersInfo.default_provider;
        let defaultModel = null;

        // Sort providers by type (commercial first, then local)
        const sortedProviders = providersInfo.providers.sort((a, b) => {
            if (a.type === 'commercial' && b.type === 'local') return -1;
            if (a.type === 'local' && b.type === 'commercial') return 1;
            return a.display_name.localeCompare(b.display_name);
        });

        // Group models by provider, highlighting configured providers and disabling unconfigured ones
        sortedProviders.forEach(provider => {
            if (provider.models && provider.models.length > 0) {
                const isConfigured = !!provider.is_configured;
                const safeGroupBase = Utils.escapeHtml(String(provider.display_name || provider.name || 'Provider'));
                const groupLabel = isConfigured ? `✅ ${safeGroupBase}` : `${safeGroupBase} (Not Configured)`;
                const labelStyle = isConfigured ? '' : ' style="color:#888"';
                optionsHtml += `<optgroup label="${groupLabel}"${labelStyle}>`;

                provider.models.forEach(model => {
                    const value = `${provider.name}/${model}`;
                    const displayName = Utils.escapeHtml(String(model));
                    const safeValue = Utils.escapeHtml(String(value));
                    const isDefault = provider.name === defaultProvider && provider.default_model === model;

                    if (isDefault) {
                        defaultModel = value;
                    }

                    const disabled = isConfigured ? '' : ' disabled';
                    const suffix = isConfigured ? '' : ' (requires API key)';
                    optionsHtml += `<option value="${safeValue}"${isDefault ? ' data-default="true"' : ''}${disabled}>${displayName}${isDefault ? ' (default)' : ''}${suffix}</option>`;
                });

                optionsHtml += '</optgroup>';
            }
        });

        // Update all model select dropdowns
        document.querySelectorAll('.llm-model-select').forEach(select => {
            const currentValue = select.value;
            const hasUseDefault = select.querySelector('option[value=""]');

            // Build the complete HTML
            let html = '';
            if (hasUseDefault && hasUseDefault.textContent.includes('Use default')) {
                html = '<option value="">Use default</option>';
            }
            html += optionsHtml;

            // Safe replace of options
            select.innerHTML = html;

            // Restore previous selection or set default
            if (currentValue) {
                select.value = currentValue;
            } else if (defaultModel && !hasUseDefault) {
                select.value = defaultModel;
            }
        });

        console.log(`Populated model dropdowns with ${providersInfo.total_configured} providers`);

    } catch (error) {
        console.error('Failed to populate model dropdowns:', error);
        // Show error in dropdowns
        document.querySelectorAll('.llm-model-select').forEach(select => {
            while (select.firstChild) select.removeChild(select.firstChild);
            const opt = document.createElement('option');
            opt.value = '';
            opt.textContent = 'Error loading models';
            select.appendChild(opt);
        });
    }
}

// Make character functions globally available immediately
(function() {
    if (typeof window !== 'undefined') {
        window.createCharacter = createCharacter;
        window.listCharacters = listCharacters;
        window.getCharacter = getCharacter;
        window.updateCharacter = updateCharacter;
        window.deleteCharacter = deleteCharacter;
        window.createConversation = createConversation;
        window.listConversations = listConversations;
        window.getConversationDetails = getConversationDetails;
        window.sendConversationMessage = sendConversationMessage;
        window.updateConversation = updateConversation;
        window.deleteConversation = deleteConversation;
        window.exportConversation = exportConversation;

        console.log('Character/conversation functions attached to window');
    }
})();

// Store provider data globally for filtering
let globalProvidersInfo = null;

// Function to filter models based on selected provider
function filterModelsByProvider(providerSelectId, modelSelectId) {
    const providerSelect = document.getElementById(providerSelectId);
    const modelSelect = document.getElementById(modelSelectId);

    if (!providerSelect || !modelSelect || !globalProvidersInfo) {
        return;
    }

    const selectedProvider = providerSelect.value;

    // Clear current options
    modelSelect.innerHTML = '';

    if (!selectedProvider) {
        // If no provider selected, show all models grouped by provider
        populateModelDropdown(modelSelect, globalProvidersInfo);
    } else {
        // Show only models for selected provider
        const provider = globalProvidersInfo.providers.find(p => p.name === selectedProvider);
        if (provider && provider.models && provider.models.length > 0) {
            // Add models without optgroup since we're showing only one provider
            provider.models.forEach(model => {
                const option = document.createElement('option');
                option.value = `${provider.name}/${model}`;
                option.textContent = model;
                modelSelect.appendChild(option);
            });

            // Select first model by default
            if (provider.models.length > 0) {
                modelSelect.value = `${provider.name}/${provider.models[0]}`;
            }
        } else {
            // No models for this provider
            const option = document.createElement('option');
            option.value = '';
            option.textContent = 'No models available for this provider';
            modelSelect.appendChild(option);
        }
    }
}

// Helper function to populate a single model dropdown
function populateModelDropdown(selectElement, providersInfo) {
    const defaultProvider = providersInfo.default_provider;
    let defaultModel = null;
    // Clear existing options
    while (selectElement.firstChild) selectElement.removeChild(selectElement.firstChild);

    // Sort providers by type (commercial first, then local)
    const sortedProviders = providersInfo.providers.sort((a, b) => {
        if (a.type === 'commercial' && b.type === 'local') return -1;
        if (a.type === 'local' && b.type === 'commercial') return 1;
        return a.display_name.localeCompare(b.display_name);
    });

    // Build groups and options via DOM APIs, with configured highlighting
    sortedProviders.forEach(provider => {
        if (provider.models && provider.models.length > 0) {
            const group = document.createElement('optgroup');
            const isConfigured = !!provider.is_configured;
            const base = String(provider.display_name || provider.name || 'Provider');
            group.label = isConfigured ? `✅ ${base}` : `${base} (Not Configured)`;
            if (!isConfigured) group.setAttribute('style', 'color:#888');
            provider.models.forEach(model => {
                const value = `${provider.name}/${model}`;
                const isDefault = provider.name === defaultProvider && provider.default_model === model;
                if (isDefault) defaultModel = value;
                const opt = document.createElement('option');
                opt.value = value;
                opt.textContent = `${model}${isDefault ? ' (default)' : ''}${isConfigured ? '' : ' (requires API key)'}`;
                if (!isConfigured) opt.disabled = true;
                if (isDefault) opt.dataset.default = 'true';
                group.appendChild(opt);
            });
            selectElement.appendChild(group);
        }
    });

    if (defaultModel) {
        selectElement.value = defaultModel;
    }
}

// Modified populateModelDropdowns to store provider data
async function populateModelDropdownsOriginal() {
    try {
        // Get available providers from API
        const providersInfo = await apiClient.getAvailableProviders();

        // Store globally for filtering
        globalProvidersInfo = providersInfo;

        if (!providersInfo || !providersInfo.providers || providersInfo.providers.length === 0) {
            console.warn('No LLM providers configured');
            // Update dropdowns to show no providers available
            document.querySelectorAll('.llm-model-select').forEach(select => {
                select.innerHTML = '<option value="">No models available - check configuration</option>';
            });
            return;
        }

        // Update all model select dropdowns
        document.querySelectorAll('.llm-model-select').forEach(select => {
            const currentValue = select.value;
            const hasUseDefault = select.querySelector('option[value=""]');

            if (hasUseDefault && hasUseDefault.textContent.includes('Use default')) {
                // Keep the "Use default" option
                const defaultOption = document.createElement('option');
                defaultOption.value = '';
                defaultOption.textContent = 'Use default';
                select.innerHTML = '';
                select.appendChild(defaultOption);
            } else {
                select.innerHTML = '';
            }

            // Populate with all models
            populateModelDropdown(select, providersInfo);

            // Restore previous selection if valid
            if (currentValue && select.querySelector(`option[value="${currentValue}"]`)) {
                select.value = currentValue;
            }
        });

        console.log(`Populated model dropdowns with ${providersInfo.total_configured} providers`);

    } catch (error) {
        console.error('Failed to populate model dropdowns:', error);
        // Show error in dropdowns
        document.querySelectorAll('.llm-model-select').forEach(select => {
            select.innerHTML = '<option value="">Error loading models</option>';
        });
    }
}

// Override the original function
populateModelDropdowns = populateModelDropdownsOriginal;

// Call populateModelDropdowns when the chat content is loaded
document.addEventListener('DOMContentLoaded', () => {
    // Check if we're on a page with model dropdowns
    if (document.querySelector('.llm-model-select')) {
        // Wait a bit for API client to initialize
        setTimeout(populateModelDropdowns, 500);
    }

    // Add event listener for provider dropdown changes
    const chatCompletionsProvider = document.getElementById('chatCompletions_provider');
    if (chatCompletionsProvider) {
        chatCompletionsProvider.addEventListener('change', () => {
            filterModelsByProvider('chatCompletions_provider', 'chatCompletions_model');
        });
    }

    // Add event listener for main chat provider dropdown
    const chatProvider = document.getElementById('chat-provider');
    if (chatProvider) {
        chatProvider.addEventListener('change', () => {
            filterModelsByProvider('chat-provider', 'chat-model');
        });
    }
});
</script> --> -->

<style>
.chat-message {
    margin-bottom: 10px;
    padding: 8px;
    border-radius: 4px;
    word-wrap: break-word;
    overflow-wrap: break-word;
}

.chat-message.user {
    background-color: #e3f2fd;
    margin-left: 20%;
}

.chat-message.assistant {
    background-color: #f5f5f5;
    margin-right: 20%;
}

.chat-message.system {
    background-color: #fff3e0;
    text-align: center;
    font-style: italic;
}

/* Mobile Responsiveness */
@media screen and (max-width: 768px) {
    .chat-message.user,
    .chat-message.assistant {
        margin-left: 0;
        margin-right: 0;
        max-width: 100%;
    }

    .chat-messages {
        height: 300px !important;
    }

    .endpoint-section {
        padding: 10px;
    }

    .form-group {
        margin-bottom: 15px;
    }

    textarea {
        font-size: 16px; /* Prevent zoom on iOS */
    }

    .btn-group {
        flex-wrap: wrap;
        gap: 5px;
    }

    .btn {
        min-width: 80px;
        padding: 10px 16px;
        font-size: 16px;
    }

    select.llm-model-select {
        width: 100%;
        margin-left: 0 !important;
        margin-top: 10px;
    }

    fieldset {
        padding: 5px;
    }

    /* Make advanced options more accessible on mobile */
    details.advanced-params summary {
        padding: 10px;
        font-size: 16px;
        background-color: #f0f0f0;
        border-radius: 5px;
    }
}

@media screen and (max-width: 480px) {
    .chat-messages {
        height: 250px !important;
    }

    .endpoint-section h2 {
        font-size: 1.2rem;
    }

    .api-button {
        width: 100%;
        padding: 12px;
        font-size: 16px;
    }
}

.typing {
    animation: pulse 1.5s infinite;
}

@keyframes pulse {
    0% { opacity: 1; }
    50% { opacity: 0.5; }
    100% { opacity: 1; }
}

.btn-group {
    display: flex;
    gap: 10px;
    align-items: center;
    flex-wrap: wrap;
}

.btn {
    padding: 8px 16px;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    font-size: 14px;
    touch-action: manipulation; /* Better touch handling */
    -webkit-tap-highlight-color: transparent; /* Remove tap highlight on iOS */
}

.btn-primary {
    background-color: #007bff;
    color: white;
}

.btn-primary:hover {
    background-color: #0056b3;
}

.btn-secondary {
    background-color: #6c757d;
    color: white;
}

.btn-secondary:hover {
    background-color: #545b62;
}
</style>

<!-- Characters Tab -->
<div id="tabCharacters" class="tab-content">
    <div class="endpoint-section" id="charactersCreate">
        <h2>
            <span class="endpoint-method post">POST</span>
            <span class="endpoint-path">/api/v1/characters - Create Character</span>
        </h2>
        <p>Create a new character for roleplay or conversation with ALL available fields.</p>

        <!-- Basic Character Information -->
        <fieldset style="margin-bottom: 15px; padding: 10px; border: 1px solid #ccc; border-radius: 3px;">
            <legend>Basic Information</legend>

            <div class="form-group">
                <label for="charactersCreate_name">Character Name <span class="required">*</span>:</label>
                <input type="text" id="charactersCreate_name" placeholder="e.g., Assistant, Teacher, Expert">
            </div>

            <div class="form-group">
                <label for="charactersCreate_description">Description:</label>
                <textarea id="charactersCreate_description" rows="3" placeholder="Brief character description..."></textarea>
            </div>

            <div class="form-group">
                <label for="charactersCreate_personality">Personality:</label>
                <textarea id="charactersCreate_personality" rows="3" placeholder="Character personality traits..."></textarea>
            </div>

            <div class="form-group">
                <label for="charactersCreate_scenario">Scenario:</label>
                <textarea id="charactersCreate_scenario" rows="3" placeholder="The setting or context where the character exists..."></textarea>
            </div>
        </fieldset>

        <!-- Conversation Settings -->
        <fieldset style="margin-bottom: 15px; padding: 10px; border: 1px solid #ccc; border-radius: 3px;">
            <legend>Conversation Settings</legend>

            <div class="form-group">
                <label for="charactersCreate_system_prompt">System Prompt:</label>
                <textarea id="charactersCreate_system_prompt" rows="5" placeholder="System instructions for the character...">You are a helpful AI assistant.</textarea>
            </div>

            <div class="form-group">
                <label for="charactersCreate_post_history_instructions">Post-History Instructions:</label>
                <textarea id="charactersCreate_post_history_instructions" rows="3" placeholder="Instructions that come after conversation history (optional)..."></textarea>
            </div>

            <div class="form-group">
                <label for="charactersCreate_first_message">First Message:</label>
                <textarea id="charactersCreate_first_message" rows="3" placeholder="Character's greeting or first message...">Hello! How can I assist you today?</textarea>
            </div>

            <div class="form-group">
                <label for="charactersCreate_message_example">Message Example:</label>
                <textarea id="charactersCreate_message_example" rows="5" placeholder="Example conversation format (optional)..."></textarea>
            </div>

            <div class="form-group">
                <label for="charactersCreate_alternate_greetings">Alternate Greetings (JSON array or comma-separated):</label>
                <textarea id="charactersCreate_alternate_greetings" rows="3" placeholder='["Hello!", "Hi there!", "Greetings!"] or comma-separated list'></textarea>
            </div>
        </fieldset>

        <!-- Metadata -->
        <fieldset style="margin-bottom: 15px; padding: 10px; border: 1px solid #ccc; border-radius: 3px;">
            <legend>Metadata</legend>

            <div class="form-group">
                <label for="charactersCreate_creator">Creator:</label>
                <input type="text" id="charactersCreate_creator" placeholder="Creator name (optional)">
            </div>

            <div class="form-group">
                <label for="charactersCreate_creator_notes">Creator Notes:</label>
                <textarea id="charactersCreate_creator_notes" rows="3" placeholder="Notes from the creator (optional)..."></textarea>
            </div>

            <div class="form-group">
                <label for="charactersCreate_character_version">Character Version:</label>
                <input type="text" id="charactersCreate_character_version" placeholder="e.g., 1.0.0">
            </div>

            <div class="form-group">
                <label for="charactersCreate_tags">Tags (comma-separated):</label>
                <input type="text" id="charactersCreate_tags" placeholder="e.g., helpful, technical, friendly">
            </div>

            <div class="form-group">
                <label for="charactersCreate_extensions">Extensions (JSON object):</label>
                <textarea id="charactersCreate_extensions" rows="3" placeholder='{"custom_field": "value", "another_field": 123}'>{}</textarea>
            </div>

            <div class="form-group">
                <label for="charactersCreate_image_base64">Character Image (Base64):</label>
                <textarea id="charactersCreate_image_base64" rows="2" placeholder="Base64 encoded image (optional, without data:image prefix)..."></textarea>
            </div>
        </fieldset>

        <button class="api-button" id="btn_createCharacter">
            Create Character
        </button>

        <h3>Response:</h3>
        <pre id="charactersCreate_response">---</pre>
    </div>

    <div class="endpoint-section" id="charactersList">
        <h2>
            <span class="endpoint-method get">GET</span>
            <span class="endpoint-path">/api/v1/characters - List Characters</span>
        </h2>
        <p>List all available characters.</p>

        <button class="api-button" id="btn_listCharacters">
            List Characters
        </button>

        <h3>Response:</h3>
        <pre id="charactersList_response">---</pre>
    </div>

    <div class="endpoint-section" id="charactersGet">
        <h2>
            <span class="endpoint-method get">GET</span>
            <span class="endpoint-path">/api/v1/characters/{character_id} - Get Character</span>
        </h2>
        <p>Get details of a specific character.</p>

        <div class="form-group">
            <label for="charactersGet_id">Character ID <span class="required">*</span>:</label>
            <input type="text" id="charactersGet_id" placeholder="Enter character ID">
        </div>

        <button class="api-button" id="btn_getCharacter">
            Get Character
        </button>

        <h3>Response:</h3>
        <pre id="charactersGet_response">---</pre>
    </div>

    <div class="endpoint-section" id="charactersUpdate">
        <h2>
            <span class="endpoint-method put">PUT</span>
            <span class="endpoint-path">/api/v1/characters/{character_id} - Update Character</span>
        </h2>
        <p>Update an existing character.</p>

        <div class="form-group">
            <label for="charactersUpdate_id">Character ID <span class="required">*</span>:</label>
            <input type="text" id="charactersUpdate_id" placeholder="Enter character ID">
        </div>

        <div class="form-group">
            <label for="charactersUpdate_payload">Update Data (JSON):</label>
            <textarea id="charactersUpdate_payload" class="code-input" rows="15">{
  "name": "Updated Character Name",
  "description": "Updated description",
  "personality": "Updated personality traits",
  "system_prompt": "Updated system prompt",
  "first_message": "Updated greeting message",
  "tags": ["tag1", "tag2"]
}</textarea>
        </div>

        <button class="api-button" id="btn_updateCharacter">
            Update Character
        </button>

        <h3>Response:</h3>
        <pre id="charactersUpdate_response">---</pre>
    </div>

    <div class="endpoint-section" id="charactersDelete">
        <h2>
            <span class="endpoint-method delete">DELETE</span>
            <span class="endpoint-path">/api/v1/characters/{character_id} - Delete Character</span>
        </h2>
        <p>Delete a character.</p>

        <div class="form-group">
            <label for="charactersDelete_id">Character ID <span class="required">*</span>:</label>
            <input type="text" id="charactersDelete_id" placeholder="Enter character ID">
        </div>

        <button class="api-button btn-danger" id="btn_deleteCharacter" data-confirm="Delete this character?">
            Delete Character
        </button>

        <h3>Response:</h3>
        <pre id="charactersDelete_response">---</pre>
    </div>
</div>

<!-- Conversations Tab -->
<div id="tabConversations" class="tab-content">
    <div class="endpoint-section" id="conversationsCreate">
        <h2>
            <span class="endpoint-method post">POST</span>
            <span class="endpoint-path">/api/v1/chats - Create Chat Session</span>
        </h2>
        <p>Start a new conversation with a character or assistant.</p>

        <div class="form-group">
            <label for="conversationsCreate_title">Conversation Title:</label>
            <input type="text" id="conversationsCreate_title" placeholder="e.g., Technical Discussion, Project Planning">
        </div>

        <div class="form-group">
            <label for="conversationsCreate_character_id">Character ID (optional):</label>
            <input type="text" id="conversationsCreate_character_id" placeholder="Character ID to use for this conversation">
        </div>

        <div class="form-group">
            <label for="conversationsCreate_system_prompt">System Prompt (optional):</label>
            <textarea id="conversationsCreate_system_prompt" rows="3" placeholder="Override character's system prompt for this conversation"></textarea>
        </div>

        <div class="form-group">
            <label for="conversationsCreate_initial_message">Initial Message:</label>
            <textarea id="conversationsCreate_initial_message" rows="3" placeholder="Your first message in the conversation"></textarea>
        </div>

        <div class="form-group">
            <label for="conversationsCreate_metadata">Metadata (JSON):</label>
            <textarea id="conversationsCreate_metadata" class="code-input" rows="3">{}</textarea>
        </div>

        <button class="api-button" id="btn_createConversation">
            Create Conversation
        </button>

        <h3>Response:</h3>
        <pre id="conversationsCreate_response">---</pre>
    </div>

    <div class="endpoint-section" id="conversationsList">
        <h2>
            <span class="endpoint-method get">GET</span>
            <span class="endpoint-path">/api/v1/chats - List Chat Sessions</span>
        </h2>
        <p>List all conversations with optional filtering.</p>

        <div class="columns">
            <div class="column">
                <div class="form-group">
                    <label for="conversationsList_character_id">Character ID (optional):</label>
                    <input type="text" id="conversationsList_character_id" placeholder="Filter by character">
                </div>
            </div>

            <div class="column">
                <div class="form-group">
                    <label for="conversationsList_limit">Limit:</label>
                    <input type="number" id="conversationsList_limit" value="20" min="1" max="100">
                </div>
            </div>
        </div>

        <button class="api-button" id="btn_listConversations">
            List Conversations
        </button>

        <h3>Response:</h3>
        <pre id="conversationsList_response">---</pre>
    </div>

    <div class="endpoint-section" id="conversationsGet">
        <h2>
            <span class="endpoint-method get">GET</span>
            <span class="endpoint-path">/api/v1/chats/{chat_id} - Get Chat Session</span>
        </h2>
        <p>Get details and messages of a specific conversation.</p>

        <div class="form-group">
            <label for="conversationsGet_id">Conversation ID <span class="required">*</span>:</label>
            <input type="text" id="conversationsGet_id" placeholder="Enter conversation ID">
        </div>

        <div class="form-group">
            <label>
                <input type="checkbox" id="conversationsGet_include_messages" checked>
                Include Messages
            </label>
        </div>

        <button class="api-button" id="btn_getConversationDetails">
            Get Conversation
        </button>

        <h3>Response:</h3>
        <pre id="conversationsGet_response">---</pre>
    </div>

    <div class="endpoint-section" id="conversationsChat">
        <h2>
            <span class="endpoint-method post">POST</span>
            <span class="endpoint-path">/api/v1/chats/{chat_id}/messages - Send Message</span>
        </h2>
        <p>Send a message to a conversation and get a response.</p>

        <div class="form-group">
            <label for="conversationsChat_id">Conversation ID <span class="required">*</span>:</label>
            <input type="text" id="conversationsChat_id" placeholder="Enter conversation ID">
        </div>

        <div class="form-group">
            <label for="conversationsChat_message">Message <span class="required">*</span>:</label>
            <textarea id="conversationsChat_message" rows="4" placeholder="Your message..."></textarea>
        </div>

        <div class="columns">
            <div class="column">
                <div class="form-group">
                    <label for="conversationsChat_model">Model (optional):</label>
                    <select id="conversationsChat_model" class="llm-model-select">
                        <option value="">Use default</option>
                    </select>
                </div>
            </div>

            <div class="column">
                <div class="form-group">
                    <label for="conversationsChat_temperature">Temperature:</label>
                    <input type="number" id="conversationsChat_temperature" value="0.7" min="0" max="2" step="0.1">
                </div>
            </div>
        </div>

        <div class="form-group">
            <label>
                <input type="checkbox" id="conversationsChat_stream">
                Stream Response
            </label>
        </div>

        <button class="api-button" id="btn_sendConversationMessage">
            Send Message
        </button>

        <h3>Response:</h3>
        <pre id="conversationsChat_response">---</pre>
    </div>

    <div class="endpoint-section" id="conversationsUpdate">
        <h2>
            <span class="endpoint-method put">PUT</span>
            <span class="endpoint-path">/api/v1/chats/{chat_id} - Update Chat Session</span>
        </h2>
        <p>Update conversation metadata or settings.</p>

        <div class="form-group">
            <label for="conversationsUpdate_id">Conversation ID <span class="required">*</span>:</label>
            <input type="text" id="conversationsUpdate_id" placeholder="Enter conversation ID">
        </div>

        <div class="form-group">
            <label for="conversationsUpdate_payload">Update Data (JSON):</label>
            <textarea id="conversationsUpdate_payload" class="code-input" rows="10">{
  "title": "Updated Title",
  "system_prompt": "Updated system prompt",
  "metadata": {
    "tags": ["important", "technical"]
  }
}</textarea>
        </div>

        <button class="api-button" id="btn_updateConversation">
            Update Conversation
        </button>

        <h3>Response:</h3>
        <pre id="conversationsUpdate_response">---</pre>
    </div>

    <div class="endpoint-section" id="conversationsDelete">
        <h2>
            <span class="endpoint-method delete">DELETE</span>
            <span class="endpoint-path">/api/v1/chats/{chat_id} - Delete Chat Session</span>
        </h2>
        <p>Delete a conversation and all its messages.</p>

        <div class="form-group">
            <label for="conversationsDelete_id">Conversation ID <span class="required">*</span>:</label>
            <input type="text" id="conversationsDelete_id" placeholder="Enter conversation ID">
        </div>

        <button class="api-button btn-danger" id="btn_deleteConversation" data-confirm="Delete this conversation and all its messages?">
            Delete Conversation
        </button>

        <h3>Response:</h3>
        <pre id="conversationsDelete_response">---</pre>
    </div>

    <div class="endpoint-section" id="conversationsExport">
        <h2>
            <span class="endpoint-method get">GET</span>
            <span class="endpoint-path">/api/v1/chats/{chat_id}/export - Export Chat Session</span>
        </h2>
        <p>Export a conversation in various formats.</p>

        <div class="form-group">
            <label for="conversationsExport_id">Conversation ID <span class="required">*</span>:</label>
            <input type="text" id="conversationsExport_id" placeholder="Enter conversation ID">
        </div>

        <div class="form-group">
            <label for="conversationsExport_format">Format:</label>
            <select id="conversationsExport_format">
                <option value="json">JSON</option>
                <option value="markdown">Markdown</option>
                <option value="txt">Plain Text</option>
            </select>
        </div>

        <button class="api-button" id="btn_exportConversation">
            Export Conversation
        </button>

        <h3>Response:</h3>
        <pre id="conversationsExport_response">---</pre>
    </div>
</div>

<!-- Scripts removed - functions now in js/tab-functions.js -->
<!-- <script>
// Characters tab functions
async function createCharacter() {
    const responseEl = document.getElementById('charactersCreate_response');
    try {
        responseEl.textContent = 'Creating character...';

        // Collect all form values
        const body = {};

        // Required field
        const name = document.getElementById('charactersCreate_name').value;
        if (!name) {
            throw new Error('Character name is required');
        }
        body.name = name;

        // Basic Information
        const description = document.getElementById('charactersCreate_description').value;
        if (description) body.description = description;

        const personality = document.getElementById('charactersCreate_personality').value;
        if (personality) body.personality = personality;

        const scenario = document.getElementById('charactersCreate_scenario').value;
        if (scenario) body.scenario = scenario;

        // Conversation Settings
        const systemPrompt = document.getElementById('charactersCreate_system_prompt').value;
        if (systemPrompt) body.system_prompt = systemPrompt;

        const postHistoryInstructions = document.getElementById('charactersCreate_post_history_instructions').value;
        if (postHistoryInstructions) body.post_history_instructions = postHistoryInstructions;

        const firstMessage = document.getElementById('charactersCreate_first_message').value;
        if (firstMessage) body.first_message = firstMessage;

        const messageExample = document.getElementById('charactersCreate_message_example').value;
        if (messageExample) body.message_example = messageExample;

        // Handle alternate_greetings - can be JSON array or comma-separated
        const alternateGreetingsValue = document.getElementById('charactersCreate_alternate_greetings').value;
        if (alternateGreetingsValue) {
            try {
                // Try parsing as JSON first
                body.alternate_greetings = JSON.parse(alternateGreetingsValue);
            } catch (e) {
                // If not JSON, treat as comma-separated list
                body.alternate_greetings = alternateGreetingsValue.split(',').map(g => g.trim()).filter(g => g);
            }
        }

        // Metadata
        const creator = document.getElementById('charactersCreate_creator').value;
        if (creator) body.creator = creator;

        const creatorNotes = document.getElementById('charactersCreate_creator_notes').value;
        if (creatorNotes) body.creator_notes = creatorNotes;

        const characterVersion = document.getElementById('charactersCreate_character_version').value;
        if (characterVersion) body.character_version = characterVersion;

        // Handle tags - comma-separated
        const tags = document.getElementById('charactersCreate_tags').value;
        if (tags) {
            body.tags = tags.split(',').map(t => t.trim()).filter(t => t);
        }

        // Handle extensions - should be JSON object
        const extensionsValue = document.getElementById('charactersCreate_extensions').value;
        if (extensionsValue && extensionsValue !== '{}') {
            try {
                body.extensions = JSON.parse(extensionsValue);
            } catch (e) {
                throw new Error('Extensions must be valid JSON');
            }
        }

        // Handle image_base64
        const imageBase64 = document.getElementById('charactersCreate_image_base64').value;
        if (imageBase64) body.image_base64 = imageBase64;

        const response = await apiClient.makeRequest('POST', '/api/v1/characters', { body });
        responseEl.textContent = JSON.stringify(response, null, 2);
        Toast.success('Character created successfully');
    } catch (error) {
        responseEl.textContent = `Error: ${error.message}`;
        Toast.error(`Failed to create character: ${error.message}`);
    }
}

async function listCharacters() {
    const responseEl = document.getElementById('charactersList_response');
    try {
        responseEl.textContent = 'Loading characters...';
        const response = await apiClient.makeRequest('GET', '/api/v1/characters');
        responseEl.textContent = JSON.stringify(response, null, 2);
    } catch (error) {
        responseEl.textContent = `Error: ${error.message}`;
        Toast.error(`Failed to list characters: ${error.message}`);
    }
}

async function getCharacter() {
    const responseEl = document.getElementById('charactersGet_response');
    try {
        const characterId = document.getElementById('charactersGet_id').value;
        if (!characterId) {
            throw new Error('Character ID is required');
        }

        responseEl.textContent = 'Loading character...';
        const response = await apiClient.makeRequest('GET', `/api/v1/characters/${characterId}`);
        responseEl.textContent = JSON.stringify(response, null, 2);
    } catch (error) {
        responseEl.textContent = `Error: ${error.message}`;
        Toast.error(`Failed to get character: ${error.message}`);
    }
}

async function updateCharacter() {
    const responseEl = document.getElementById('charactersUpdate_response');
    try {
        const characterId = document.getElementById('charactersUpdate_id').value;
        if (!characterId) {
            throw new Error('Character ID is required');
        }

        const payload = document.getElementById('charactersUpdate_payload').value;
        const body = JSON.parse(payload);

        responseEl.textContent = 'Updating character...';
        const response = await apiClient.makeRequest('PUT', `/api/v1/characters/${characterId}`, { body });
        responseEl.textContent = JSON.stringify(response, null, 2);
        Toast.success('Character updated successfully');
    } catch (error) {
        responseEl.textContent = `Error: ${error.message}`;
        Toast.error(`Failed to update character: ${error.message}`);
    }
}

async function deleteCharacter() {
    const responseEl = document.getElementById('charactersDelete_response');
    try {
        const characterId = document.getElementById('charactersDelete_id').value;
        if (!characterId) {
            throw new Error('Character ID is required');
        }

        responseEl.textContent = 'Deleting character...';
        const response = await apiClient.makeRequest('DELETE', `/api/v1/characters/${characterId}`);
        responseEl.textContent = response ? JSON.stringify(response, null, 2) : 'Character deleted successfully';
        Toast.success('Character deleted successfully');
    } catch (error) {
        responseEl.textContent = `Error: ${error.message}`;
        Toast.error(`Failed to delete character: ${error.message}`);
    }
}

// Conversations tab functions
async function createConversation() {
    const responseEl = document.getElementById('conversationsCreate_response');
    try {
        responseEl.textContent = 'Creating conversation...';

        const metadata = document.getElementById('conversationsCreate_metadata').value;

        const body = {
            title: document.getElementById('conversationsCreate_title').value,
            initial_message: document.getElementById('conversationsCreate_initial_message').value
        };

        // Add optional fields if provided
        const characterId = document.getElementById('conversationsCreate_character_id').value;
        if (characterId) body.character_id = characterId;

        const systemPrompt = document.getElementById('conversationsCreate_system_prompt').value;
        if (systemPrompt) body.system_prompt = systemPrompt;

        if (metadata && metadata.trim() !== '{}') {
            body.metadata = JSON.parse(metadata);
        }

        const response = await apiClient.makeRequest('POST', '/api/v1/chats', { body });
        responseEl.textContent = JSON.stringify(response, null, 2);
        Toast.success('Conversation created successfully');
    } catch (error) {
        responseEl.textContent = `Error: ${error.message}`;
        Toast.error(`Failed to create conversation: ${error.message}`);
    }
}

async function listConversations() {
    const responseEl = document.getElementById('conversationsList_response');
    try {
        responseEl.textContent = 'Loading conversations...';

        const params = new URLSearchParams();
        const characterId = document.getElementById('conversationsList_character_id').value;
        if (characterId) params.append('character_id', characterId);

        const limit = document.getElementById('conversationsList_limit').value;
        if (limit) params.append('limit', limit);

        const queryString = params.toString();
        const url = queryString ? `/api/v1/chats?${queryString}` : '/api/v1/chats';

        const response = await apiClient.makeRequest('GET', url);
        responseEl.textContent = JSON.stringify(response, null, 2);
    } catch (error) {
        responseEl.textContent = `Error: ${error.message}`;
        Toast.error(`Failed to list conversations: ${error.message}`);
    }
}

async function getConversationDetails() {
    const responseEl = document.getElementById('conversationsGet_response');
    try {
        const conversationId = document.getElementById('conversationsGet_id').value;
        if (!conversationId) {
            throw new Error('Conversation ID is required');
        }

        responseEl.textContent = 'Loading conversation...';

        const includeMessages = document.getElementById('conversationsGet_include_messages').checked;
        const params = includeMessages ? '?include_messages=true' : '';

        const response = await apiClient.makeRequest('GET', `/api/v1/chats/${conversationId}`);
        responseEl.textContent = JSON.stringify(response, null, 2);
    } catch (error) {
        responseEl.textContent = `Error: ${error.message}`;
        Toast.error(`Failed to get conversation: ${error.message}`);
    }
}

async function sendConversationMessage() {
    const responseEl = document.getElementById('conversationsChat_response');
    try {
        const conversationId = document.getElementById('conversationsChat_id').value;
        if (!conversationId) {
            throw new Error('Conversation ID is required');
        }

        const message = document.getElementById('conversationsChat_message').value;
        if (!message) {
            throw new Error('Message is required');
        }

        responseEl.textContent = 'Sending message...';

        const body = { message };

        // Add optional fields
        const model = document.getElementById('conversationsChat_model').value;
        if (model) body.model = model;

        const temperature = document.getElementById('conversationsChat_temperature').value;
        if (temperature) body.temperature = parseFloat(temperature);

        const stream = document.getElementById('conversationsChat_stream').checked;
        body.stream = stream;

        if (stream) {
            // Handle streaming response
            responseEl.textContent = 'Streaming response...\n';
            const headers = (() => {
                const h = { 'Content-Type': 'application/json', 'Accept': 'text/event-stream' };
                try {
                    if (apiClient && apiClient.token) {
                        if (apiClient.authMode === 'single-user' || apiClient.preferApiKeyInMultiUser) h['X-API-KEY'] = apiClient.token;
                        else h['Authorization'] = `Bearer ${apiClient.token}`;
                    }
                } catch (e) {}
                return h;
            })();
            const response = await fetch(`${apiClient.baseUrl}/api/v1/chats/${conversationId}/messages`, {
                method: 'POST',
                headers,
                body: JSON.stringify({ role: 'user', content: body.message || '' })
            });

            if (!response.ok) {
                throw new Error(`HTTP ${response.status}: ${response.statusText}`);
            }

            const reader = response.body.getReader();
            const decoder = new TextDecoder();

            while (true) {
                const { done, value } = await reader.read();
                if (done) break;

                const chunk = decoder.decode(value);
                const lines = chunk.split('\n');

                for (const line of lines) {
                    if (line.startsWith('data: ')) {
                        const data = line.slice(6);
                        if (data === '[DONE]') continue;

                        try {
                            const parsed = JSON.parse(data);
                            if (parsed.choices?.[0]?.delta?.content) {
                                responseEl.textContent += parsed.choices[0].delta.content;
                            }
                        } catch (e) {
                            console.error('Error parsing SSE data:', e);
                        }
                    }
                }
            }
        } else {
            // Handle non-streaming response
            const response = await apiClient.makeRequest('POST', `/api/v1/chats/${conversationId}/messages`, { body: { role: 'user', content: body.message || '' } });
            responseEl.textContent = JSON.stringify(response, null, 2);
        }

        Toast.success('Message sent successfully');
    } catch (error) {
        responseEl.textContent = `Error: ${error.message}`;
        Toast.error(`Failed to send message: ${error.message}`);
    }
}

async function updateConversation() {
    const responseEl = document.getElementById('conversationsUpdate_response');
    try {
        const conversationId = document.getElementById('conversationsUpdate_id').value;
        if (!conversationId) {
            throw new Error('Conversation ID is required');
        }

        const payload = document.getElementById('conversationsUpdate_payload').value;
        const body = JSON.parse(payload);

        responseEl.textContent = 'Updating conversation...';
        const filtered = {};
        if (body.title) filtered.title = body.title;
        if (typeof body.rating !== 'undefined') filtered.rating = body.rating;
        const response = await apiClient.makeRequest('PUT', `/api/v1/chats/${conversationId}`, { body: filtered });
        responseEl.textContent = JSON.stringify(response, null, 2);
        Toast.success('Conversation updated successfully');
    } catch (error) {
        responseEl.textContent = `Error: ${error.message}`;
        Toast.error(`Failed to update conversation: ${error.message}`);
    }
}

async function deleteConversation() {
    const responseEl = document.getElementById('conversationsDelete_response');
    try {
        const conversationId = document.getElementById('conversationsDelete_id').value;
        if (!conversationId) {
            throw new Error('Conversation ID is required');
        }

        responseEl.textContent = 'Deleting conversation...';
        const response = await apiClient.makeRequest('DELETE', `/api/v1/chats/${conversationId}`);
        responseEl.textContent = response ? JSON.stringify(response, null, 2) : 'Conversation deleted successfully';
        Toast.success('Conversation deleted successfully');
    } catch (error) {
        responseEl.textContent = `Error: ${error.message}`;
        Toast.error(`Failed to delete conversation: ${error.message}`);
    }
}

async function exportConversation() {
    const responseEl = document.getElementById('conversationsExport_response');
    try {
        const conversationId = document.getElementById('conversationsExport_id').value;
        if (!conversationId) {
            throw new Error('Conversation ID is required');
        }

        const format = document.getElementById('conversationsExport_format').value;

        responseEl.textContent = 'Exporting conversation...';
        const response = await apiClient.makeRequest('GET', `/api/v1/chats/${conversationId}/export?format=${format}`);

        // Handle different formats
        if (format === 'json') {
            responseEl.textContent = JSON.stringify(response, null, 2);
        } else {
            responseEl.textContent = response;
        }

        Toast.success('Conversation exported successfully');
    } catch (error) {
        responseEl.textContent = `Error: ${error.message}`;
        Toast.error(`Failed to export conversation: ${error.message}`);
    }
}
</script>
